package cn.com.bluemoon.daps.system.service.impl;

import cn.com.bluemoon.daps.common.domain.UserInfoHolder;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.exception.DapException;
import cn.com.bluemoon.daps.common.toolkit.BmAssetUtils;
import cn.com.bluemoon.daps.system.entity.DapSystemBizLine;
import cn.com.bluemoon.daps.system.entity.DapSystemBizLineDetail;
import cn.com.bluemoon.daps.system.mapper.DapSystemBizLineMapper;
import cn.com.bluemoon.daps.system.service.BizLineDeletePredicate;
import cn.com.bluemoon.daps.system.service.DapSystemBizLineDetailService;
import cn.com.bluemoon.daps.system.service.DapSystemBizLineService;
import cn.com.bluemoon.daps.system.service.RowDeletePredicate;
import cn.com.bluemoon.daps.system.vo.BizLineDetailRequestVo;
import cn.com.bluemoon.daps.system.vo.BizLineDetailResponseVo;
import cn.com.bluemoon.daps.system.vo.BizLineRequestVo;
import cn.com.bluemoon.daps.system.vo.BizLineResponseVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统业务线 服务实现类
 * </p>
 *
 * @author admin
 * @since 2021-09-23
 */
@Slf4j
@Service
public class DapSystemBizLineServiceImpl extends ServiceImpl<DapSystemBizLineMapper, DapSystemBizLine>
        implements DapSystemBizLineService {

    @Autowired
    private BizLineDeletePredicate[] bizLineDeletePredicates;

    @Autowired
    private DapSystemBizLineDetailService bizLineDetailService;


    @Override
    @Transactional(rollbackFor = {DapException.class, RuntimeException.class})
    public Integer saveOrUpdateBizLine(BizLineRequestVo bizLineRequestVo, Integer bizLineId, UserInfoHolder.UserInfo userInfo) {
        DapSystemBizLine model = bizLineRequestVo.toModel();
        model.setBizLineId(bizLineId);
        DapSystemBizLine bizLine = saveOrUpdateBizLine(model);
        List<DapSystemBizLineDetail> details = bizLineRequestVo.getDetails().stream().map(BizLineDetailRequestVo::toModel)
                .peek(d -> d.setBizLineId(bizLine.getBizLineId())).collect(Collectors.toList());
        if (!details.isEmpty() && bizLineId != null) {
            checkBizLineDetails(details);
            bizLineDetailService.resetBizLineDetails(bizLineId, details);
        }
        return bizLine.getBizLineId();
    }

    private void checkBizLineDetails(List<DapSystemBizLineDetail> details) {
        for (DapSystemBizLineDetail each : details) {
            String admins = each.getAdmins();
            String develops = each.getDevelops();
            if (admins != null) {
                boolean hadRepeat = Arrays.stream(admins.split(",")).distinct().count() != Arrays.stream(admins.split(",")).count();
                BmAssetUtils.isFalse(hadRepeat, "管理员不能重复");
            }
            if (develops != null) {
                boolean hadRepeat = Arrays.stream(develops.split(",")).distinct().count() != Arrays.stream(develops.split(",")).count();
                BmAssetUtils.isFalse(hadRepeat, "开发者不能重复");
            }
            if (!StringUtils.isEmpty(develops) && !StringUtils.isEmpty(admins)) {
                Set<String> adminSet = Arrays.stream(admins.split(",")).collect(Collectors.toSet());
                Set<String> developsSet = Arrays.stream(develops.split(",")).collect(Collectors.toSet());
                List<String> collect = adminSet.stream().filter(a -> developsSet.contains(a)).collect(Collectors.toList());
                BmAssetUtils.isFalse(!collect.isEmpty(), String.format("用户%s不能同时为管理员和开发人员", collect));
            }
        }
    }

    @Override
    public List<BizLineDetailResponseVo> findBizLineDetails(@Nullable Integer bizLineId) {
        if (bizLineId == null) {
            return bizLineDetailService.findDefaultCommonDetailVos();
        } else {
            return bizLineDetailService.findBizLineDetailVos(bizLineId);
        }
    }

    @Override
    public void deleteBizLineDetailByBizLineIdAndSystemId(@Nullable Integer bizLineId, String systemId) {
        if (StringUtils.isBlank(systemId)){
            log.info("系统id为空，不清除业务线与系统管理信息");
            return;
        }
        LambdaUpdateWrapper<DapSystemBizLineDetail> deleteWrapper = bizLineDetailService.bmLambdaUpdate()
                .eq(bizLineId != null, DapSystemBizLineDetail::getBizLineId, bizLineId)
                .eq(DapSystemBizLineDetail::getSystemId, systemId);
        boolean delete = bizLineDetailService.remove(deleteWrapper);
        log.info("删除业务线id={}，系统id={}，情况：{}", bizLineId, systemId, delete);
    }

    @Override
    @Transactional(rollbackFor = {DapException.class, RuntimeException.class})
    public DapSystemBizLine saveOrUpdateBizLine(DapSystemBizLine bizLineBo) {
        checkRequestBizLine(bizLineBo);
        if (bizLineBo.getBizLineId() == null) {
            return saveWithPredicate(bizLineBo);
        } else {
            return updateWithPredicate(bizLineBo);
        }
    }

    /**
     * 新增或修改进行数据校验
     */
    private void checkRequestBizLine(DapSystemBizLine bizLine) {
        if (bizLine != null) {
            // ignore
        }
    }

    @Override
    @Transactional(rollbackFor = {DapException.class, RuntimeException.class})
    public boolean deleteBizLineById(Integer bizLineId) {
        DapSystemBizLine bizLine = checkBizLine(bizLineId);
        boolean remove;
        // 增加业务逻辑判断是否能删除改业务线
        if (bizLineDeletePredicates != null) {
            for (BizLineDeletePredicate bizLineDeletePredicate : bizLineDeletePredicates) {
                RowDeletePredicate.Result<Integer> predicate = bizLineDeletePredicate.predicate(bizLineId);
                if (predicate != null && !predicate.isCanDelete()) {
                    throw new DapException(predicate.getMessage());
                }
            }
        }
        remove = removeByBizLineId(bizLineId, bizLine);
        // 关系信息
        bizLineDetailService.removeByBizLineId(bizLineId);
        return remove;
    }

    @Override
    public BizLineResponseVo appendUserInfoExtra(BizLineResponseVo responseVo) {
        Integer bizLineId = responseVo.getBizLineId();
        // 2022/4/6 细化业务线与系统人员关系信息
        responseVo.setDetails(bizLineDetailService.findBizLineDetailVos(bizLineId));
        return responseVo;
    }

    private boolean removeByBizLineId(Integer bizLineId, DapSystemBizLine bizLine) {
        boolean remove = removeById(bizLineId);
        log.info("删除业务线{}, status:{}", bizLine, remove);
        return remove;
    }

    private DapSystemBizLine updateWithPredicate(DapSystemBizLine bizLineBo) {
        Integer bizLineId = bizLineBo.getBizLineId();
        checkBizLine(bizLineId);
        LambdaQueryWrapper<DapSystemBizLine> exits = bmLambdaQuery().ne(DapSystemBizLine::getBizLineId, bizLineId).and(wrapper ->
                wrapper.eq(DapSystemBizLine::getCode, bizLineBo.getCode()).or().eq(DapSystemBizLine::getCodeName, bizLineBo.getCodeName()));
        return saveOrUpdateWithPredicate(bizLineBo, exits);
    }

    private DapSystemBizLine checkBizLine(Integer bizLineId) {
        DapSystemBizLine dbBizLine = getById(bizLineId);
        BmAssetUtils.isTrue(dbBizLine != null && BmStatus.ON.equals(dbBizLine.getBmStatus()), "业务线不存在");
        return dbBizLine;
    }

    private DapSystemBizLine saveWithPredicate(DapSystemBizLine bizLineBo) {
        LambdaQueryWrapper<DapSystemBizLine> exits = bmLambdaQuery().and(wrapper -> wrapper.eq(DapSystemBizLine::getCode, bizLineBo.getCode())
                .or().eq(DapSystemBizLine::getCodeName, bizLineBo.getCodeName()));
        return saveOrUpdateWithPredicate(bizLineBo, exits);
    }

    private DapSystemBizLine saveOrUpdateWithPredicate(DapSystemBizLine bizLineBo, LambdaQueryWrapper<DapSystemBizLine> exits) {
        List<DapSystemBizLine> hadBizLines = list(exits);
        if (hadBizLines.isEmpty()) {
            saveOrUpdate(bizLineBo);
            return bizLineBo;
        } else {
            throw new DapException("业务线名称或编码已存在");
        }
    }
}
